#pragma once
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <functional>
#include <cstring>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "Socket.hpp"
#include "Util.hpp"
#include "log.hpp"

const std::string SEP = "\r\n";
const int SEP_LEN = SEP.size();
const char FSEP = ' '; // 请求行分隔符
const int FSEP_LEN = sizeof(FSEP);
const std::string HTTP_VERSION = "HTTP/1.1";
const std::string rootdir = "./wwwroot";
const std::string defaultURL = "/index.html";

class Session
{
public:
    Session()
    {
    }
    Session(const std::string &username, const std::string &passwd, uint32_t sessionID)
        : _username(username), _passwd(passwd), _sessionID(sessionID)
    {
    }

private:
    std::string _username;
    std::string _passwd;
    uint32_t _sessionID;
};

static std::unordered_map<std::string, std::string> ups = {{"laolu", "1234"}, {"1561421081", "5326784q"}};

class HttpRequest
{
public:
    bool Deserialize(std::string s)
    {
        // 1.获取http请求报文的请求行
        if (!Util::ReadOneLine(s, &_reqLine, SEP)) // 读取错误，返回404?TODO
        {
            return false;
        }

        // std::cout << "获取请求行后的字符串: " << s << std::endl;

        // 2.获取报头和正文
        while (!s.empty())
        {
            std::string line;
            Util::ReadOneLine(s, &line, SEP);
            if (line.empty()) // 读到了空行
                break;

            _headers.insert(Util::ParseHeader(line));
        }
        _body = s;

        // 3.分析请求报文的请求方法和请求资源路径
        int l = _reqLine.find(FSEP);
        _method = _reqLine.substr(0, l++);
        int r = _reqLine.find(FSEP, l);
        _url = _reqLine.substr(l, r - l);
        if (_url == "/")
            _url = defaultURL;

        // 4.获取url后缀
        size_t pos = _url.rfind('.');
        if (pos == std::string::npos)
            return false;
        _suffix = _url.substr(pos, _url.size() - pos);

        return true;
    }

    const std::string &GetUrl() const
    {
        return _url;
    }

    void ChangUrl(std::string newurl)
    {
        _url = newurl;
    }

    const std::string &GetSuffix() const
    {
        return _suffix;
    }

    const std::string &GetMethod() const
    {
        return _method;
    }

    const std::string &GetBody() const
    {
        return _body;
    }

    bool GetCookie(std::string *cookie)
    {
        for (const auto &header : _headers)
        {
            if (header.first == "Cookie")
            {
                *cookie = header.second;
                return true;
            }
        }
        return false;
    }

    void Show()
    {
        std::cout << "请求行: " << _reqLine << std::endl;
        std::cout << "URL: " << _url << std::endl;

        int i = 0;
        for (auto &kv : _headers)
        {
            std::cout << "[" << i++ << "] " << kv.first << "->" << kv.second << std::endl;
        }

        std::cout << "正文: " << _body << std::endl;
    }

private:
    std::string _reqLine;                                  // 请求行
    std::string _url;                                      // 请求资源文件路径
    std::string _suffix;                                   // URL的文件后缀
    std::string _method;                                   // 请求方法
    std::unordered_map<std::string, std::string> _headers; // 报头
    std::string _body;                                     // 正文
};

class HttpResponse
{
public:
    static std::string ToStatDesc(uint32_t sc) // 将状态码转换为状态描述
    {
        switch (sc)
        {
        case 200:
            return "OK";
        case 404:
            return "Not Found";
        case 302:
            return "Found";
        case 500:
            return "Internal Server Error";
        }
    }

public:
    HttpResponse(uint32_t statCode = 200) : _statCode(statCode) {}

    bool Serialize(std::string *s)
    {
        // 1.响应行
        std::string respLine;
        respLine = HTTP_VERSION + FSEP + std::to_string(_statCode) + FSEP + ToStatDesc(_statCode) + SEP;
        *s += respLine;

        // 2.headers
        for (const auto &kv : _headers)
        {
            std::string header = kv.first + ": " + kv.second + SEP;
            *s += header;
        }

        // 3.空行
        *s += SEP;

        // 4.正文
        *s += _body;
        // _bodyLen = _body.size();
        return true;
    }

    void AddHeader(const std::string &key, const std::string &val)
    {
        _headers[key] = val;
    }

    void SetStateCode(uint32_t sc)
    {
        _statCode = sc;
    }

    std::string &GetBody()
    {
        return _body;
    }

private:
    std::unordered_map<std::string, std::string> _headers; // 报头
    std::string _body;                                     // 正文（资源）
    // int _bodyLen;                                          // 正文长度
    uint32_t _statCode; // 状态码
};

class HttpServer;

struct ThreadData
{
    ThreadData(int cfd, HttpServer *ts) : _cfd(cfd), _ts(ts) {}
    int _cfd;
    HttpServer *_ts;
};

class HttpServer
{
    using cbfunc_t = std::function<std::string(std::string, HttpServer *)>;

public:
    HttpServer(cbfunc_t cb, uint16_t port) : _cb(cb), _port(port) {}

    void Initial()
    {
        _listenSock.Socket();
        _listenSock.Bind(_port);
        _listenSock.Listen();
    }

    void Start()
    {
        while (true)
        {
            int cfd = _listenSock.Accept();
            if (cfd < 0)
            {
                LogMessage(INFO, "accept fail\n");
                continue;
            }
            LogMessage(INFO, "新客户端已接入, client fd: %d\n", cfd);

            pthread_t pid;
            pthread_create(&pid, nullptr, threadRoutine, new ThreadData(cfd, this));
        }
    }

    void Service(int cfd)
    {
        while (true)
        {
            // 1.recv -- 从客户端读取一个http package
            std::string request;
            std::string inbuf;

            while (true)
            {
                int ret = Util::ReadHttpRequest(cfd, inbuf, &request);
                if (ret == 0)
                    // 读取了一个完整的http报文
                    break;
                if (ret == 1)
                    // 客户端关闭连接
                    goto CLOSE;
                else
                {
                    // 未读取完整http报文，继续读取
                    LogMessage(DEBUG, "err code: %d", ret);
                    continue;
                }
            }

            // std::string request;
            // if (!Util::ReadHttpRequest(cfd, &request))
            // {
            //     LogMessage(ERROR, "recv error\n");
            //     break;
            // }

            std::cout << "收到的请求：" << std::endl;
            std::cout << request << std::endl;

            // 2.业务处理
            std::string response = _cb(request, this);

            std::cout << "处理的响应：" << std::endl;
            std::cout << response << std::endl;

            // 3.send -- 返回响应到客户端
            if (!Util::SendHttpResponse(cfd, response))
            {
                LogMessage(ERROR, "send error\n");
                break;
            }
        }
    CLOSE:
        close(cfd);
    }

    static void *threadRoutine(void *args)
    {
        ThreadData *td = static_cast<ThreadData *>(args);
        td->_ts->Service(td->_cfd);
        pthread_detach(pthread_self());
        return nullptr;
    }

    bool CheckSession(const std::string &cookie)
    {
        // 提取cookie中的sessionID并通过sessionID检测对于session是否存在
        // cookie = "sessionID=XXXX"
        size_t pos = cookie.find("sessionID");
        pos += strlen("sessionID") + 1;
        uint32_t sessionID = std::stoi(cookie.substr(pos, cookie.size() - pos));
        return _sessions.find(sessionID) != _sessions.end();
    }

    void AddSession(uint32_t ID, const Session &s)
    {
        _sessions[ID] = s;
    }

private:
    Sock _listenSock;
    uint16_t _port;
    cbfunc_t _cb;
    std::unordered_map<uint32_t, Session> _sessions; // 存放用户的session信息
};